﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Flagwind.ComponentModel.DataAnnotations;
using Flagwind.Plugins;

namespace Flagwind.Web.Plugins
{
	public class PluginModelValidatorProvider : DataAnnotationsModelValidatorProvider
	{
		#region 成员字段

		private PluginContext _pluginContext;

		#endregion

		#region 构造方法

		public PluginModelValidatorProvider(PluginContext pluginContext)
		{
			if(pluginContext == null)
				throw new ArgumentNullException(nameof(pluginContext));

			_pluginContext = pluginContext;
		}

		#endregion

		#region 重写方法

		protected override IEnumerable<ModelValidator> GetValidators(ModelMetadata metadata, ControllerContext context, IEnumerable<Attribute> attributes)
		{
			object validationRuleNames = null;
			context.RouteData.DataTokens.TryGetValue("validationRules", out validationRuleNames);

			attributes = this.FilterAttributes(attributes, validationRuleNames as IEnumerable<string>);

			return base.GetValidators(metadata, context, attributes);
		}

		#endregion

		#region 私有方法

		private IEnumerable<Attribute> FilterAttributes(IEnumerable<Attribute> attributes, IEnumerable<string> rules)
		{
			var validatorAttributes = attributes.OfType<ValidatorAttribute>();
			var nonValidatorAttributes = attributes.Except(validatorAttributes);
			var validValidatorAttributes = new List<ValidatorAttribute>();

			// 处理验证规则为空，即未声明 ValidatorAttribute。
			if(rules == null)
			{
				// 将所有默认规则(未指定RuleName的规则)添加至最终的验证规则中。
				validValidatorAttributes.AddRange(validatorAttributes.Where(v => string.IsNullOrEmpty(v.RuleName)));

				return nonValidatorAttributes.Union(validValidatorAttributes);
			}

			// 根据验证规则的类型进行分组
			var groups = from validator in validatorAttributes group validator by validator.GetType();

			foreach(var rule in rules)
			{
				foreach(var group in groups)
				{
					var validatorAttribute = group.FirstOrDefault(v => string.Compare(v.RuleName, rule, StringComparison.OrdinalIgnoreCase) == 0);

					if(validatorAttribute != null)
						validValidatorAttributes.Add(validatorAttribute);
				}
			}

			return nonValidatorAttributes.Union(validValidatorAttributes);
		}

		#endregion
	}
}
